package Algorithms;

import General.AdjacencyMatrix;
import General.DistanceMatrix;
import General.MembershipMatrix;

public class ExtendedFuzzyCMeans extends ClusteringAlgorithm {

	public ExtendedFuzzyCMeans(AdjacencyMatrix a, DistanceMatrix d, double m,
			double eps, int[] centers) {
		super(a, d, m, eps, centers);
		
	}
	
	public double inclusionMeasure(int k, int l)
	{
		double sum_up=0, sum_down=0;
		for (int j=0; j<n; j++)
		{
			sum_up+=Math.min(u.get(j, k),u.get(j, l));
			sum_down+=u.get(j, k);
		}
		return sum_up/sum_down;
	}
	
	public double similarityDegree(int k, int l)
	{
		return Math.max(inclusionMeasure(k,l),inclusionMeasure(l,k));
	}
	
	public int[] maxSimilarityDegree()
	{
		int res[] = new int[2];
		double max=0;
		double temp;
		for (int i=0; i<c; i++)
			for(int j=0; j<i; j++)
			{
				temp=similarityDegree(i, j);
				if (temp>max)
				{
					max=temp;
					res[0]=i;
					res[1]=j;
					
				}
				
					
			}
		return res;
	}

	public double alpha()
	{
		return 1/((double)(c-1));
	}

	public MembershipMatrix run()
	{
		double change;
		fillMembershipMatrix(); // initial U matrix
		do
		{
			
			u.print();
			System.out.println();
			
			for(int i=0;i<c; i++)
				System.out.print(centers[i]+", ");
			
			
			// calculate new center for each cluster:
			for (int k=0; k<c; k++)
			{
			double[] sum = new double[n];
			double sum_down=0;
			for (int i=0; i<n; i++)
			{
				vectorSum(sum, vectorMul( u.get(i, k), a.getVector(i)));
				sum_down+=u.get(i, k);
			}
			for (int i=0; i<n; i++)
			{
				sum[i]/=sum_down;
			}
			centers[k]=closestNode(sum);
			}
			// calculate U
			change=fillMembershipMatrix();
			// find 2 clusters to merge (if needed):
			int[] similar=maxSimilarityDegree();
			if (similarityDegree(similar[0], similar[1])>alpha())
			{
				u.merge(similar[0], similar[1]);
				c--;
			}
			
		}
		while (change>=eps);
		
		return u;
	}
}
